#ifndef NETSERVICE_H
#define NETSERVICE_H

#include "core_global.h"
#include "tcpconnectionpool.h"
#include "asyncservice.h"
#include <boost/noncopyable.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/thread/mutex.hpp>

class TcpConnection;
class TcpAcceptor;

class CORE_EXPORT NetService :
        protected boost::noncopyable
{
public:
    typedef boost::function< size_t (size_t) > Filter;
    typedef boost::function< void (unsigned long, size_t, int) > Completion;
    typedef boost::function< void (unsigned long, int) > Accepter;

    typedef boost::shared_ptr< TcpAcceptor > AcceptorPtr;
    typedef boost::shared_ptr< TcpConnection > ConnectionPtr;

    typedef boost::mutex Mutex;
    typedef boost::unordered_set< ConnectionPtr > UnorderedSet;
    typedef boost::unordered_map< unsigned long, ConnectionPtr > UnorderedMap;
    typedef boost::system::error_code ErrorCode;

public:
    NetService(AsyncService &service);
    ~NetService();

    int initialize();

    int open(const std::string &host, unsigned short port, int listenCount);

    void close();

    void close(unsigned long key);

    int endpoint(unsigned long key, std::string &host, unsigned short &port);

    void accept(BOOST_ASIO_MOVE_ARG(Accepter) a);

    void read(unsigned long key, void *buf, size_t size,
              BOOST_ASIO_MOVE_ARG(Filter) f,
              BOOST_ASIO_MOVE_ARG(Completion) c);

    void write(unsigned long key, const void *buf, size_t size,
               BOOST_ASIO_MOVE_ARG(Filter) f,
               BOOST_ASIO_MOVE_ARG(Completion) c);

protected:
    void onAccepted(Accepter a, ConnectionPtr con, int err);

    size_t isComplete(Filter f, size_t size);

    void onComplete(Completion c, ConnectionPtr con, size_t size, int err);

    void onTrash();

private:
    AsyncService &m_service;

    AcceptorPtr m_acceptor;

    TcpConnectionPool m_connectionPool;

    UnorderedMap m_connectionMap;

    UnorderedSet m_trash;

    Mutex m_acceptorLock;

    Mutex m_cmLock;

    Mutex m_trashLock;
};

#endif // NETSERVICE_H
